package BVRClient;

import java.net.InetSocketAddress;
import java.nio.charset.Charset;
import java.util.Vector;

import org.apache.mina.common.ConnectFuture;
import org.apache.mina.filter.codec.ProtocolCodecFilter;
import org.apache.mina.filter.codec.textline.TextLineCodecFactory;
import org.apache.mina.transport.socket.nio.SocketConnector;
import org.newdawn.slick.GameContainer;
import org.newdawn.slick.Graphics;
import org.newdawn.slick.Image;
import org.newdawn.slick.SlickException;
import org.newdawn.slick.state.BasicGameState;
import org.newdawn.slick.state.StateBasedGame;

/**
 * The Blue vs Red: Arena Gameplay State.
 * @author Jesse Gill
 * @author Shannon Setter
 */
public class BVRC_GamePlayState extends BasicGameState
{
	private int stateID = 0;
	private BVRC_Map currentMap = null;
	private BVRC_Camera camera = new BVRC_Camera();
	
	public Vector<BVRC_Player> players = new Vector<BVRC_Player>();
	public Vector<BVRC_Projectile> projectiles = new Vector<BVRC_Projectile>();
	
	public Vector<BVRC_Projectile> removeProjectiles = new Vector<BVRC_Projectile>();
	
	public BVRC_Player localPlayer = null;
	
	SocketConnector connector = null;
	
	/**
	 * Constructor that sets the state ID.
	 * @param stateID
	 */
	public BVRC_GamePlayState(int stateID)
    {
        this.stateID = stateID;
    }
	
	/**
	 * 
	 * @param id
	 * @return the player id, null if no player is found
	 */
	public BVRC_Player getPlayerFromID(int id)
	{
		for (int i = 0; i < players.size(); i++)
		{
			if (players.get(i).getPlayerID() == id)
				return players.get(i);
		}
		
		return null;
	}
	
	/**
	 * @param gc
	 * @param sb
	 */
	@Override
    public void enter(GameContainer gc, StateBasedGame sb) throws SlickException
    {
		players.clear();
		projectiles.clear();
		
        super.enter(gc, sb);
        
        connector = new SocketConnector();
        
        connector.getFilterChain().addLast("codec", new ProtocolCodecFilter(new TextLineCodecFactory(Charset.forName("US-ASCII"))));
        
        @SuppressWarnings("unused")
		ConnectFuture cf = connector.connect(new InetSocketAddress(BVRC_Settings.currentServerAddress, BVRC_Settings.currentServerPort), new BVRClientHandler(this));
        
        currentMap = new BVRC_Map();
        
        // error if the current map couldn't be loaded
        if (! currentMap.open("res/maps/" + BVRC_Settings.currentMap + ".map"))
        	currentMap = null;
    }
	
	/**
	 * @param gc
	 * @param sb
	 */
	@Override
    public void leave(GameContainer gc, StateBasedGame sb) throws SlickException
    {
        super.leave(gc, sb);
        
        currentMap = null;
        
        players.clear();
    }
	
	/**
	 * @return stateID
	 */
	@Override
	public int getID()
	{
		return stateID;
	}
	
	/**
	 * @param gc
	 * @param sb
	 */
	@Override
	public void init(GameContainer gc, StateBasedGame sb) throws SlickException
	{
		camera.setVisibleRect(new BVRC_Rect(0, 0, gc.getWidth(), gc.getHeight()));
		
		BVRC_ImageResources.blueTeamSprite = new Image("res/player/blue.png");
		BVRC_ImageResources.redTeamSprite = new Image("res/player/red.png");
		BVRC_ImageResources.blueTeamBullet = new Image("res/projectiles/blue.png");
		BVRC_ImageResources.redTeamBullet = new Image("res/projectiles/red.png");
	}
	
	/**
	 * @param gc
	 * @param sb
	 * @param g
	 */
	@Override
	public void render(GameContainer gc, StateBasedGame sb, Graphics g) throws SlickException
	{
		if (currentMap != null)
			currentMap.draw(-(int)camera.getVisibleRect().x, -(int)camera.getVisibleRect().y);
		
		if (localPlayer == null)
			return;
		
		for (int i = 0; i < players.size(); i++)
		{
			if (players.get(i) != localPlayer)
				players.get(i).draw(camera);
		}
		
		for (int i = 0; i < projectiles.size(); i++)
		{
			projectiles.get(i).draw(camera);
		}
		
		localPlayer.draw(camera);
	}
	
	/**
	 * @param gc
	 * @param sb
	 * @param delta
	 */
	@Override
	public void update(GameContainer gc, StateBasedGame sb, int delta) throws SlickException
	{
		if (localPlayer != null)
		{
			camera.update(localPlayer);
		}
		
		handleInput(gc);
		
		for (int i = 0; i < players.size(); i++)
		{
			players.get(i).updateMovement(i, delta, this.currentMap);
		}
		
		removeProjectiles.clear();
		
		for (int i = 0; i < projectiles.size(); i++)
		{
			if (projectiles.get(i).updateMovement(i, delta, this.currentMap) == false)
			{
				removeProjectiles.add(projectiles.get(i)); // delete projectile
			}
			
			for (int x = 0; x < players.size(); x++)
			{
				if (projectiles.get(i).playerCollision(players.get(x)))
				{
					if (projectiles.get(i).getTeam() != players.get(x).getTeam())
					{
						if (players.get(x) == localPlayer)
						{
							BVRC_PacketGenerator.playerDeath().send(BVRC_Settings.session);
						}
						
						removeProjectiles.add(projectiles.get(i)); // delete projectile
					}
				}
			}
		}
		
		// Clean up deleted projectiles
		for (int i = 0; i < removeProjectiles.size(); i++)
		{
			projectiles.remove(removeProjectiles.get(i));
		}
		
		removeProjectiles.clear();
	}
	
	/**
	 * 
	 * @param gc
	 */
	private void handleInput(GameContainer gc)
	{
		
	}
	
	/**
	 * @param oldx
	 * @param oldy
	 * @param newx
	 * @param newy
	 */
	public void mouseMoved(int oldx, int oldy, int newx, int newy)
	{
		if (localPlayer == null)
			return;
		
		localPlayer.rotateFacePoint(new BVRC_Point(newx, newy), camera);
		
		BVRC_PacketGenerator.playerRotation(localPlayer.getRotation()).send(BVRC_Settings.session);
	}
	
	public void mousePressed(int button, int x, int y)
	{
		if (localPlayer == null)
			return;
		
		if (button == 0)
		{
			BVRC_Projectile projectile = new BVRC_Projectile(BVRC_Settings.projectileSpeed, localPlayer);
			
			projectiles.add(projectile);
			
			BVRC_PacketGenerator.createProjectile(projectile).send(BVRC_Settings.session);
		}
	}
	
	/**
	 * @param key
	 * @param c
	 */
	public void keyPressed(int key, char c)
	{
		if (localPlayer == null)
			return;
		
		if (c == 'w')
		{
			localPlayer.setMovementSpeedY(BVRC_Settings.movementSpeed);
		}
		if (c == 's')
		{
			localPlayer.setMovementSpeedY(-BVRC_Settings.movementSpeed);
		}
		if (c == 'a')
		{
			localPlayer.setMovementSpeedX(-BVRC_Settings.movementSpeed);
		}
		if (c == 'd')
		{
			localPlayer.setMovementSpeedX(BVRC_Settings.movementSpeed);
		}
		
		BVRC_PacketGenerator.playerVelocity(localPlayer).send(BVRC_Settings.session);
	}
	
	/**
	 * @param key
	 * @param c
	 */
	public void keyReleased(int key, char c)
	{
		if (localPlayer == null)
			return;
		
		if (c == 'w' || c == 's')
		{
			localPlayer.setMovementSpeedY(0);
		}
		if (c == 'a' || c == 'd')
		{
			localPlayer.setMovementSpeedX(0);
		}
		
		BVRC_PacketGenerator.playerVelocity(localPlayer).send(BVRC_Settings.session);
		BVRC_PacketGenerator.playerPosition(localPlayer).send(BVRC_Settings.session);
	}
}
